/**
 * @Description: gitlab响应提问题
 * @author Beon
 * @date 2021/1/25
*/
import {LzgitCliFile, lzgitJson} from '../utils/lzgitCliFile';
import {OraLoading} from '../decorators/oraLoading';
import * as inquirer from 'inquirer';
import {GitLab} from '../api/gitLab';
import {ErrorCatch} from '../decorators/errorCatch';
import {BranchOrigin} from '../git/branchOrigin';
import {Log} from '../git/log';

type MRMEESAGEOBJ = {
    branch: string
    title: string
    desc: string
    users: string
}

export class GitLabInquirer {
    @OraLoading.beProxy
    static status: OraLoading;
    private static Branchs: {name: string, value: string}[]
    private static Members: {name: string, value: string}[]
    private static ProjectId: string
    private static Authorization: string
    private static authorizationInquirer = {
        type: 'input',
        name: 'Authorization',
        message: '请填入您的访问令牌'
    }
    private static isReWrite = {
        type: 'confirm',
        name: 'check',
        message: '是否重新输入信息'
    }
    private static mrMessageInquirer = [{
        type: 'list',
        name: 'branch',
        message: '请选择合入的主分支',
        choices: []
    },
    {
        type: 'input',
        name: 'title',
        message: '请输入合并标题',
        default: ''
    },
    {
        type: 'input',
        name: 'desc',
        message: '请输入合并描述'
    },
    {
        type: 'list',
        name: 'users',
        message: '选择合并用户',
        choices: []
    }]

    /**
     * 检查提交信息
     * @returns {Promise<void>}
     * @param {String} url gitlab地址域
     */
    static async checkLabInquirer(url: string): Promise<void> {
        if (!await this.checkAuthorization(url)) {
            this.status.oraLoadingStop();

            await this.inputAuthorization(url);

            this.status.oraLoadingStart();
        }

        await this.linkGitLab(url);
    }

    /**
     * 处理提问信息
     * @param origin
     * @returns {Promise<void>}
     * @param url
     */
    static async dealLabInquirer(origin: string, url: string): Promise<void> {
        await this.getProjectId(origin, url);

        await this.getBranch(url);

        await this.getMembers(url);
    }

    /**
     * 提交mr主进程
     * @returns {Promise<{web_url: string}>}
     * @param url
     */
    static async gitlabInquirer(url: string): Promise<{'web_url': string}> {
        const MRMEESAGE = await this.messageInquirer();

        return await this.mrPost(MRMEESAGE, url);
    }

    /**
     * 提交mr请求
     * @returns {Promise<any>}
     * @param MRMEESAGE
     * @param url
     */
    @ErrorCatch.errorExit('发送mr请求失败，请再次尝试')
    private static async mrPost(MRMEESAGE: MRMEESAGEOBJ, url: string): Promise< {'web_url': string}> {
        return await GitLab.mergeRequests({
            'source_branch': BranchOrigin.gitBranch,
            'target_branch': MRMEESAGE.branch,
            'title': MRMEESAGE.title,
            'assignee_id': MRMEESAGE.users,
            'description': MRMEESAGE.desc,
            'remove_source_branch': true
        }, {
            headers: {
                'PRIVATE-TOKEN': this.Authorization,
            }
        }, {
            projectId: this.ProjectId
        }, url);
    }

    /**
     * 输入提交mr信息
     * @returns {Promise<void>}
     */
    private static async messageInquirer(): Promise<MRMEESAGEOBJ> {
        await this.dealInquirerMessage();

        this.status.oraLoadingStop();

        const MRMEESAGE = await inquirer.prompt(this.mrMessageInquirer);

        this.status.oraLoadingStart();

        return MRMEESAGE;
    }

    /**
     * 处理提交信息
     */
    private static async dealInquirerMessage(): Promise<void> {
        this.mrMessageInquirer[0].choices = this.Branchs.filter((item) => item.value !== BranchOrigin.gitBranch);
        this.mrMessageInquirer[1].default = await Log.lastLogTagName();
        this.mrMessageInquirer[3].choices = this.Members;
    }

    /**
     * 获取项目id
     * @param origin
     * @returns {Promise<void>}
     * @param url
     */
    @ErrorCatch.errorExit('查询项目出现错误，请确保当前项目在所选择远程库中')
    private static async getProjectId(origin: string, url: string): Promise<void> {
        let projects = await GitLab.projectGet({
            params: {
                search: origin.split('/')[origin.split('/').length - 1]
            },
            headers: {
                'PRIVATE-TOKEN': this.Authorization,
            }
        }, {}, url);

        projects = projects.filter((item) => origin.includes(item.path_with_namespace));

        if (projects.length > 1) {
            console.log('项目管理有问题，请联系jira项目管理员'.error);
            process.exit(1);
        }

        this.ProjectId = projects[0].id;
    }

    /**
     * 获取项目分支情况
     * @param url
     * @return {Promise<void>}
     */
    // @ErrorCatch.errorExit('获取项目分支出现错误，请重试')
    private static async getBranch(url: string): Promise<void> {
        const branchs = await GitLab.projectBranch({
            headers: {
                'PRIVATE-TOKEN': this.Authorization,
            }
        }, {
            projectId: this.ProjectId
        }, url);

        if (!branchs.length) {
            console.log('项目分支出现问题，请联系jira项目管理员'.error);
            process.exit(1);
        }

        this.Branchs = branchs.map((item) => ({
            name: item.name,
            value: item.name
        }));
    }

    /**
     * 获取mr人员列表
     * @returns {Promise<void>}
     * @param url
     */
    private static async getMembers(url): Promise<void> {
        const members = await GitLab.projectMember({
            headers: {
                'PRIVATE-TOKEN': this.Authorization,
            }
        }, {
            projectId: this.ProjectId
        }, url);

        if (!members.length) {
            console.log('项目人员出现问题，请联系jira项目管理员'.error);
            process.exit(1);
        }

        this.Members = members.reduce((all, item) => {
            if (item.access_level > 30){
                all.push({
                    name: item.name,
                    value: item.id
                });
            }
            return all;
        }, []);
    }

    /**
     * 测试gitlab链接是否正常
     * @param {String} url gitlab地址域
     * @returns {Promise<void>}
     */
    private static async linkGitLab(url: string): Promise<void> {
        try {
            await GitLab.userCheck({
                headers: {
                    'PRIVATE-TOKEN': this.Authorization,
                }
            }, {}, url);
        } catch (e) {
            console.log('\n链接gitlab失败'.debug);
            console.log(`\n${e.stack}`.debug);
            await this.removePassword(url);
            process.exit(1);
        }
    }

    /**
     * 输入登录信息
     * @param {String} url gitlab地址域
     * @returns {Promise<void>}
     */
    private static async inputAuthorization(url: string): Promise<void> {
        const getMessage = await inquirer
            .prompt([this.authorizationInquirer]);

        this.Authorization = getMessage.Authorization;

        await LzgitCliFile.wirteFile({
            [url]: getMessage.Authorization
        });
    }

    /**
     * 删除错误账号密码
     url
     * @returns {Promise<void>}
     */
    private static async removePassword(url: string): Promise<void> {
        this.status.oraLoadingStop();

        const getMessage = await inquirer
            .prompt([this.isReWrite]);

        if (getMessage.check) {
            await LzgitCliFile.wirteFile({
                [url]: '',
                git: ''
            });
        }

        this.status.oraLoadingStart();
    }

    /**
     * 判断gitlab信息是否存在
     * @param {String} url gitlab地址域
     * @returns {Promise<boolean>}
     */
    private static async checkAuthorization(url: string): Promise<boolean> {
        try {
            const json = await LzgitCliFile.getFileData([url]) as lzgitJson;

            if (!json || !json[url]){
                return false;
            }

            this.Authorization = json[url];
            return true;
        } catch (e) {
            return false;
        }
    }
}
